Spring BootでAPIサーバアプリケーションを書く
よく訓練されたアップル信者、都元です。ガンガンいきますよ。
前回は、Spring BootでWebアプリを書きました。しかし、モバイルのバックエンドや、リッチなフロントエンドを持つアプリケーションに対しては、JSONをやり取りするようなAPIサーバを書く機会が増えていると思います。
現時点において、APIサーバの入出力フォーマットのデファクトスタンダードはJSONであると思います。先日までのサンプルアプリケーションbersesrkerは、GET /users
に対して下記のような text/plain
を返していました。
User(username=miyamoto, password=$2a$10$cPnF0sq.bCPHeGuzVagOgOmbe2spT1Uh1k9LyuS0jzb5F3Lm.9kEy), User(username=yokota, password=$2a$10$nkvNPCb3Y1z/GSearD7s7OBdS9BoLBss3D4enbFQIgNJDvr0Xincm)
願わくば、下記のような application/json
を返すAPIを実装したいものです。
[ { "username": "miyamoto", "password": "$2a$10$cPnF0sq.bCPHeGuzVagOgOmbe2spT1Uh1k9LyuS0jzb5F3Lm.9kEy" }, { "username": "yokota", "password": "$2a$10$nkvNPCb3Y1z/GSearD7s7OBdS9BoLBss3D4enbFQIgNJDvr0Xincm" } ]
ハンドラメソッドで自作のクラスを返してみる
@RequestMapping(value = "/users", method = RequestMethod.GET) @Transactional @ResponseBody public ResponseEntity<?> users() { log.debug("users"); Iterable<User> users = userRepos.findAll(); return ResponseEntity.ok(users); }
こんな風に何も考えずに、User
の集合を返すことによって、それが実現できたらいいよなぁ、って思いませんか。
でもUser
というクラスは自分で作ったものだし、どのようにJSONに変換すべきか判断が付かないのが一般的でしょう。どうせ、これじゃRuntimeExceptionが発生するんだろうという諦めと、もしかしたらSpring Bootならやってくれるかもしれない、という淡い期待を抱きながら、いざ実行。 → /diff
$ curl -s http://localhost:8080/users [{"username":"miyamoto","password":"$2a$10$cPnF0sq.bCPHeGuzVagOgOmbe2spT1Uh1k9LyuS0jzb5F3Lm.9kEy"},{"username":"yokota","password":"$2a$10$nkvNPCb3Y1z/GSearD7s7OBdS9BoLBss3D4enbFQIgNJDvr0Xincm"}]
キタ━━━━(゚∀゚)━━━━!!
あっけなさ過ぎますね。
passwordフィールドは出力したくない問題
さて、パスワードはハッシュ化しているとは言え出力したくないですね。もう一工夫して、ここは隠してみましょう。
そもそもJavaオブジェクトをJSON形式に変換しているのはJacksonというライブラリです。Jacksonの基本的な使い方は、こう!
@Data @AllArgsConstructor @NoArgsConstructor public class HogeBean { String str; int num; boolean bool; }
public static void main(String[] args) throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); String json = objectMapper.writeValueAsString(new HogeBean("foo", 1, true)); System.out.println(json); HogeBean obj = objectMapper.readValue(json, HogeBean.class); System.out.println(obj); }
結果は、こう!
{"str":"foo","num":1,"bool":true} HogeBean(str=foo, num=1, bool=true)
あー、もうなんて直感的なんでしょうか。さらにJacksonには様々なアノテーションが用意されており、これらを活用することによってJSONとObject間の変換処理を柔軟に制御できます。下記にメジャーどころを挙げますが、その他にも色々あります。
@JsonAnyGetter
@JsonAnySetter
@JsonCreator
@JsonIgnore
@JsonInclude
@JsonProperty
この中でそれっぽい奴、、、@JsonIgnore
ですね。これを User#password
につけてみましょう。
public class User { // (ry @Getter @Setter @Column(name = "password") @JsonIgnore private String password; }
$ curl -s http://localhost:8080/users | jq . [ { "username": "miyamoto" }, { "username": "yokota" } ]
めでたし。
恒例の、動かしてみようのコーナー
$ git clone https://github.com/classmethod-aws/berserker.git $ cd berserker $ git checkout 13.0 $ ./gradlew bootRun
まぁ、いつもの感じでやってみてください。